home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / a_utils / perl / perl5a1.lha / perl5alpha1 / do / unpack < prev    next >
Encoding:
Text File  |  1992-08-15  |  12.0 KB  |  562 lines

  1. int
  2. do_unpack(TARG,gimme,arglast)
  3. STR *TARG;
  4. int gimme;
  5. int *arglast;
  6. {
  7.     STR **st = stack->ary_array;
  8.     register int sp = arglast[0] + 1;
  9.     register char *pat = str_get(st[sp++]);
  10.     register char *s = str_get(st[sp]);
  11.     char *strend = s + st[sp--]->str_cur;
  12.     char *strbeg = s;
  13.     register char *patend = pat + st[sp]->str_cur;
  14.     int datumtype;
  15.     register int len;
  16.     register int bits;
  17.  
  18.     /* These must not be in registers: */
  19.     short ashort;
  20.     int aint;
  21.     long along;
  22. #ifdef QUAD
  23.     quad aquad;
  24. #endif
  25.     unsigned short aushort;
  26.     unsigned int auint;
  27.     unsigned long aulong;
  28. #ifdef QUAD
  29.     unsigned quad auquad;
  30. #endif
  31.     char *aptr;
  32.     float afloat;
  33.     double adouble;
  34.     int checksum = 0;
  35.     unsigned long culong;
  36.     double cdouble;
  37.  
  38.     if (gimme != G_ARRAY) {        /* arrange to do first one only */
  39.     /*SUPPRESS 530*/
  40.     for (patend = pat; !isALPHA(*patend) || *patend == 'x'; patend++) ;
  41.     if (index("aAbBhH", *patend) || *pat == '%') {
  42.         patend++;
  43.         while (isDIGIT(*patend) || *patend == '*')
  44.         patend++;
  45.     }
  46.     else
  47.         patend++;
  48.     }
  49.     sp--;
  50.     while (pat < patend) {
  51.       reparse:
  52.     datumtype = *pat++;
  53.     if (pat >= patend)
  54.         len = 1;
  55.     else if (*pat == '*') {
  56.         len = strend - strbeg;    /* long enough */
  57.         pat++;
  58.     }
  59.     else if (isDIGIT(*pat)) {
  60.         len = *pat++ - '0';
  61.         while (isDIGIT(*pat))
  62.         len = (len * 10) + (*pat++ - '0');
  63.     }
  64.     else
  65.         len = (datumtype != '@');
  66.     switch(datumtype) {
  67.     default:
  68.         break;
  69.     case '%':
  70.         if (len == 1 && pat[-1] != '1')
  71.         len = 16;
  72.         checksum = len;
  73.         culong = 0;
  74.         cdouble = 0;
  75.         if (pat < patend)
  76.         goto reparse;
  77.         break;
  78.     case '@':
  79.         if (len > strend - strbeg)
  80.         fatal("@ outside of string");
  81.         s = strbeg + len;
  82.         break;
  83.     case 'X':
  84.         if (len > s - strbeg)
  85.         fatal("X outside of string");
  86.         s -= len;
  87.         break;
  88.     case 'x':
  89.         if (len > strend - s)
  90.         fatal("x outside of string");
  91.         s += len;
  92.         break;
  93.     case 'A':
  94.     case 'a':
  95.         if (len > strend - s)
  96.         len = strend - s;
  97.         if (checksum)
  98.         goto uchar_checksum;
  99.         TARG = Str_new(35,len);
  100.         str_nset(TARG,s,len);
  101.         s += len;
  102.         if (datumtype == 'A') {
  103.         aptr = s;    /* borrow register */
  104.         s = TARG->str_ptr + len - 1;
  105.         while (s >= TARG->str_ptr && (!*s || isSPACE(*s)))
  106.             s--;
  107.         *++s = '\0';
  108.         TARG->str_cur = s - TARG->str_ptr;
  109.         s = aptr;    /* unborrow register */
  110.         }
  111.         (void)astore(stack, ++sp, str_2mortal(TARG));
  112.         break;
  113.     case 'B':
  114.     case 'b':
  115.         if (pat[-1] == '*' || len > (strend - s) * 8)
  116.         len = (strend - s) * 8;
  117.         TARG = Str_new(35, len + 1);
  118.         TARG->str_cur = len;
  119.         TARG->str_pok = 1;
  120.         aptr = pat;            /* borrow register */
  121.         pat = TARG->str_ptr;
  122.         if (datumtype == 'b') {
  123.         aint = len;
  124.         for (len = 0; len < aint; len++) {
  125.             if (len & 7)        /*SUPPRESS 595*/
  126.             bits >>= 1;
  127.             else
  128.             bits = *s++;
  129.             *pat++ = '0' + (bits & 1);
  130.         }
  131.         }
  132.         else {
  133.         aint = len;
  134.         for (len = 0; len < aint; len++) {
  135.             if (len & 7)
  136.             bits <<= 1;
  137.             else
  138.             bits = *s++;
  139.             *pat++ = '0' + ((bits & 128) != 0);
  140.         }
  141.         }
  142.         *pat = '\0';
  143.         pat = aptr;            /* unborrow register */
  144.         (void)astore(stack, ++sp, str_2mortal(TARG));
  145.         break;
  146.     case 'H':
  147.     case 'h':
  148.         if (pat[-1] == '*' || len > (strend - s) * 2)
  149.         len = (strend - s) * 2;
  150.         TARG = Str_new(35, len + 1);
  151.         TARG->str_cur = len;
  152.         TARG->str_pok = 1;
  153.         aptr = pat;            /* borrow register */
  154.         pat = TARG->str_ptr;
  155.         if (datumtype == 'h') {
  156.         aint = len;
  157.         for (len = 0; len < aint; len++) {
  158.             if (len & 1)
  159.             bits >>= 4;
  160.             else
  161.             bits = *s++;
  162.             *pat++ = hexdigit[bits & 15];
  163.         }
  164.         }
  165.         else {
  166.         aint = len;
  167.         for (len = 0; len < aint; len++) {
  168.             if (len & 1)
  169.             bits <<= 4;
  170.             else
  171.             bits = *s++;
  172.             *pat++ = hexdigit[(bits >> 4) & 15];
  173.         }
  174.         }
  175.         *pat = '\0';
  176.         pat = aptr;            /* unborrow register */
  177.         (void)astore(stack, ++sp, str_2mortal(TARG));
  178.         break;
  179.     case 'c':
  180.         if (len > strend - s)
  181.         len = strend - s;
  182.         if (checksum) {
  183.         while (len-- > 0) {
  184.             aint = *s++;
  185.             if (aint >= 128)    /* fake up signed chars */
  186.             aint -= 256;
  187.             culong += aint;
  188.         }
  189.         }
  190.         else {
  191.         while (len-- > 0) {
  192.             aint = *s++;
  193.             if (aint >= 128)    /* fake up signed chars */
  194.             aint -= 256;
  195.             TARG = Str_new(36,0);
  196.             str_numset(TARG,(double)aint);
  197.             (void)astore(stack, ++sp, str_2mortal(TARG));
  198.         }
  199.         }
  200.         break;
  201.     case 'C':
  202.         if (len > strend - s)
  203.         len = strend - s;
  204.         if (checksum) {
  205.           uchar_checksum:
  206.         while (len-- > 0) {
  207.             auint = *s++ & 255;
  208.             culong += auint;
  209.         }
  210.         }
  211.         else {
  212.         while (len-- > 0) {
  213.             auint = *s++ & 255;
  214.             TARG = Str_new(37,0);
  215.             str_numset(TARG,(double)auint);
  216.             (void)astore(stack, ++sp, str_2mortal(TARG));
  217.         }
  218.         }
  219.         break;
  220.     case 's':
  221.         along = (strend - s) / sizeof(short);
  222.         if (len > along)
  223.         len = along;
  224.         if (checksum) {
  225.         while (len-- > 0) {
  226.             Copy(s,&ashort,1,short);
  227.             s += sizeof(short);
  228.             culong += ashort;
  229.         }
  230.         }
  231.         else {
  232.         while (len-- > 0) {
  233.             Copy(s,&ashort,1,short);
  234.             s += sizeof(short);
  235.             TARG = Str_new(38,0);
  236.             str_numset(TARG,(double)ashort);
  237.             (void)astore(stack, ++sp, str_2mortal(TARG));
  238.         }
  239.         }
  240.         break;
  241.     case 'v':
  242.     case 'n':
  243.     case 'S':
  244.         along = (strend - s) / sizeof(unsigned short);
  245.         if (len > along)
  246.         len = along;
  247.         if (checksum) {
  248.         while (len-- > 0) {
  249.             Copy(s,&aushort,1,unsigned short);
  250.             s += sizeof(unsigned short);
  251. #ifdef HAS_NTOHS
  252.             if (datumtype == 'n')
  253.             aushort = ntohs(aushort);
  254. #endif
  255. #ifdef HAS_VTOHS
  256.             if (datumtype == 'v')
  257.             aushort = vtohs(aushort);
  258. #endif
  259.             culong += aushort;
  260.         }
  261.         }
  262.         else {
  263.         while (len-- > 0) {
  264.             Copy(s,&aushort,1,unsigned short);
  265.             s += sizeof(unsigned short);
  266.             TARG = Str_new(39,0);
  267. #ifdef HAS_NTOHS
  268.             if (datumtype == 'n')
  269.             aushort = ntohs(aushort);
  270. #endif
  271. #ifdef HAS_VTOHS
  272.             if (datumtype == 'v')
  273.             aushort = vtohs(aushort);
  274. #endif
  275.             str_numset(TARG,(double)aushort);
  276.             (void)astore(stack, ++sp, str_2mortal(TARG));
  277.         }
  278.         }
  279.         break;
  280.     case 'i':
  281.         along = (strend - s) / sizeof(int);
  282.         if (len > along)
  283.         len = along;
  284.         if (checksum) {
  285.         while (len-- > 0) {
  286.             Copy(s,&aint,1,int);
  287.             s += sizeof(int);
  288.             if (checksum > 32)
  289.             cdouble += (double)aint;
  290.             else
  291.             culong += aint;
  292.         }
  293.         }
  294.         else {
  295.         while (len-- > 0) {
  296.             Copy(s,&aint,1,int);
  297.             s += sizeof(int);
  298.             TARG = Str_new(40,0);
  299.             str_numset(TARG,(double)aint);
  300.             (void)astore(stack, ++sp, str_2mortal(TARG));
  301.         }
  302.         }
  303.         break;
  304.     case 'I':
  305.         along = (strend - s) / sizeof(unsigned int);
  306.         if (len > along)
  307.         len = along;
  308.         if (checksum) {
  309.         while (len-- > 0) {
  310.             Copy(s,&auint,1,unsigned int);
  311.             s += sizeof(unsigned int);
  312.             if (checksum > 32)
  313.             cdouble += (double)auint;
  314.             else
  315.             culong += auint;
  316.         }
  317.         }
  318.         else {
  319.         while (len-- > 0) {
  320.             Copy(s,&auint,1,unsigned int);
  321.             s += sizeof(unsigned int);
  322.             TARG = Str_new(41,0);
  323.             str_numset(TARG,(double)auint);
  324.             (void)astore(stack, ++sp, str_2mortal(TARG));
  325.         }
  326.         }
  327.         break;
  328.     case 'l':
  329.         along = (strend - s) / sizeof(long);
  330.         if (len > along)
  331.         len = along;
  332.         if (checksum) {
  333.         while (len-- > 0) {
  334.             Copy(s,&along,1,long);
  335.             s += sizeof(long);
  336.             if (checksum > 32)
  337.             cdouble += (double)along;
  338.             else
  339.             culong += along;
  340.         }
  341.         }
  342.         else {
  343.         while (len-- > 0) {
  344.             Copy(s,&along,1,long);
  345.             s += sizeof(long);
  346.             TARG = Str_new(42,0);
  347.             str_numset(TARG,(double)along);
  348.             (void)astore(stack, ++sp, str_2mortal(TARG));
  349.         }
  350.         }
  351.         break;
  352.     case 'V':
  353.     case 'N':
  354.     case 'L':
  355.         along = (strend - s) / sizeof(unsigned long);
  356.         if (len > along)
  357.         len = along;
  358.         if (checksum) {
  359.         while (len-- > 0) {
  360.             Copy(s,&aulong,1,unsigned long);
  361.             s += sizeof(unsigned long);
  362. #ifdef HAS_NTOHL
  363.             if (datumtype == 'N')
  364.             aulong = ntohl(aulong);
  365. #endif
  366. #ifdef HAS_VTOHL
  367.             if (datumtype == 'V')
  368.             aulong = vtohl(aulong);
  369. #endif
  370.             if (checksum > 32)
  371.             cdouble += (double)aulong;
  372.             else
  373.             culong += aulong;
  374.         }
  375.         }
  376.         else {
  377.         while (len-- > 0) {
  378.             Copy(s,&aulong,1,unsigned long);
  379.             s += sizeof(unsigned long);
  380.             TARG = Str_new(43,0);
  381. #ifdef HAS_NTOHL
  382.             if (datumtype == 'N')
  383.             aulong = ntohl(aulong);
  384. #endif
  385. #ifdef HAS_VTOHL
  386.             if (datumtype == 'V')
  387.             aulong = vtohl(aulong);
  388. #endif
  389.             str_numset(TARG,(double)aulong);
  390.             (void)astore(stack, ++sp, str_2mortal(TARG));
  391.         }
  392.         }
  393.         break;
  394.     case 'p':
  395.         along = (strend - s) / sizeof(char*);
  396.         if (len > along)
  397.         len = along;
  398.         while (len-- > 0) {
  399.         if (sizeof(char*) > strend - s)
  400.             break;
  401.         else {
  402.             Copy(s,&aptr,1,char*);
  403.             s += sizeof(char*);
  404.         }
  405.         TARG = Str_new(44,0);
  406.         if (aptr)
  407.             str_set(TARG,aptr);
  408.         (void)astore(stack, ++sp, str_2mortal(TARG));
  409.         }
  410.         break;
  411. #ifdef QUAD
  412.     case 'q':
  413.         while (len-- > 0) {
  414.         if (s + sizeof(quad) > strend)
  415.             aquad = 0;
  416.         else {
  417.             Copy(s,&aquad,1,quad);
  418.             s += sizeof(quad);
  419.         }
  420.         TARG = Str_new(42,0);
  421.         str_numset(TARG,(double)aquad);
  422.         (void)astore(stack, ++sp, str_2mortal(TARG));
  423.         }
  424.         break;
  425.     case 'Q':
  426.         while (len-- > 0) {
  427.         if (s + sizeof(unsigned quad) > strend)
  428.             auquad = 0;
  429.         else {
  430.             Copy(s,&auquad,1,unsigned quad);
  431.             s += sizeof(unsigned quad);
  432.         }
  433.         TARG = Str_new(43,0);
  434.         str_numset(TARG,(double)auquad);
  435.         (void)astore(stack, ++sp, str_2mortal(TARG));
  436.         }
  437.         break;
  438. #endif
  439.     /* float and double added gnb@melba.bby.oz.au 22/11/89 */
  440.     case 'f':
  441.     case 'F':
  442.         along = (strend - s) / sizeof(float);
  443.         if (len > along)
  444.         len = along;
  445.         if (checksum) {
  446.         while (len-- > 0) {
  447.             Copy(s, &afloat,1, float);
  448.             s += sizeof(float);
  449.             cdouble += afloat;
  450.         }
  451.         }
  452.         else {
  453.         while (len-- > 0) {
  454.             Copy(s, &afloat,1, float);
  455.             s += sizeof(float);
  456.             TARG = Str_new(47, 0);
  457.             str_numset(TARG, (double)afloat);
  458.             (void)astore(stack, ++sp, str_2mortal(TARG));
  459.         }
  460.         }
  461.         break;
  462.     case 'd':
  463.     case 'D':
  464.         along = (strend - s) / sizeof(double);
  465.         if (len > along)
  466.         len = along;
  467.         if (checksum) {
  468.         while (len-- > 0) {
  469.             Copy(s, &adouble,1, double);
  470.             s += sizeof(double);
  471.             cdouble += adouble;
  472.         }
  473.         }
  474.         else {
  475.         while (len-- > 0) {
  476.             Copy(s, &adouble,1, double);
  477.             s += sizeof(double);
  478.             TARG = Str_new(48, 0);
  479.             str_numset(TARG, (double)adouble);
  480.             (void)astore(stack, ++sp, str_2mortal(TARG));
  481.         }
  482.         }
  483.         break;
  484.     case 'u':
  485.         along = (strend - s) * 3 / 4;
  486.         TARG = Str_new(42,along);
  487.         while (s < strend && *s > ' ' && *s < 'a') {
  488.         int a,b,c,d;
  489.         char hunk[4];
  490.  
  491.         hunk[3] = '\0';
  492.         len = (*s++ - ' ') & 077;
  493.         while (len > 0) {
  494.             if (s < strend && *s >= ' ')
  495.             a = (*s++ - ' ') & 077;
  496.             else
  497.             a = 0;
  498.             if (s < strend && *s >= ' ')
  499.             b = (*s++ - ' ') & 077;
  500.             else
  501.             b = 0;
  502.             if (s < strend && *s >= ' ')
  503.             c = (*s++ - ' ') & 077;
  504.             else
  505.             c = 0;
  506.             if (s < strend && *s >= ' ')
  507.             d = (*s++ - ' ') & 077;
  508.             else
  509.             d = 0;
  510.             hunk[0] = a << 2 | b >> 4;
  511.             hunk[1] = b << 4 | c >> 2;
  512.             hunk[2] = c << 6 | d;
  513.             str_ncat(TARG,hunk, len > 3 ? 3 : len);
  514.             len -= 3;
  515.         }
  516.         if (*s == '\n')
  517.             s++;
  518.         else if (s[1] == '\n')        /* possible checksum byte */
  519.             s += 2;
  520.         }
  521.         (void)astore(stack, ++sp, str_2mortal(TARG));
  522.         break;
  523.     }
  524.     if (checksum) {
  525.         TARG = Str_new(42,0);
  526.         if (index("fFdD", datumtype) ||
  527.           (checksum > 32 && index("iIlLN", datumtype)) ) {
  528.         double modf();
  529.         double trouble;
  530.  
  531.         adouble = 1.0;
  532.         while (checksum >= 16) {
  533.             checksum -= 16;
  534.             adouble *= 65536.0;
  535.         }
  536.         while (checksum >= 4) {
  537.             checksum -= 4;
  538.             adouble *= 16.0;
  539.         }
  540.         while (checksum--)
  541.             adouble *= 2.0;
  542.         along = (1 << checksum) - 1;
  543.         while (cdouble < 0.0)
  544.             cdouble += adouble;
  545.         cdouble = modf(cdouble / adouble, &trouble) * adouble;
  546.         str_numset(TARG,cdouble);
  547.         }
  548.         else {
  549.         if (checksum < 32) {
  550.             along = (1 << checksum) - 1;
  551.             culong &= (unsigned long)along;
  552.         }
  553.         str_numset(TARG,(double)culong);
  554.         }
  555.         (void)astore(stack, ++sp, str_2mortal(TARG));
  556.         checksum = 0;
  557.     }
  558.     }
  559.     return sp;
  560. }
  561.  
  562.